package edu.tec.mty.core;

import edu.tec.mty.core.connection.*;
import edu.tec.mty.core.modules.*;
import edu.tec.mty.core.modules.models.*;

public class Controller {

	private Connect connect;
	private String teamName;
	private char typeOfAgent;
	private String mySide;
	private int number;
	private Information information;
	private Dispatcher sender;
	private Reader reader;
	private Commands commands;
	private boolean isConnected;
	
	public Controller() {
		this.isConnected = false;
	}
	
	public boolean setTeamName(String teamName) {
		if (this.isConnected) {
			return false;
		} else {
			this.teamName = teamName;
			return true;
		}
	}
	
	public boolean setTypeOfAgent(char typeOfAgent) {
		if (this.isConnected) {
			return false;
		} else {
			this.typeOfAgent = typeOfAgent;
			return true;
		}
	}
	
	public void connect(String hostname) throws Exception {
		System.out.println("Attempting to connect");
		String message = "(init " + this.teamName + " (version 15)";
		switch (this.typeOfAgent) {
			case 'p':
				this.connect = new Connect(hostname, 6000);
				message = message + ")";
				break;
			case 'g':
				this.connect = new Connect(hostname, 6000);
				message = message + " (goalie))";
				break;
			case 't':
				this.connect = new Connect(hostname, 6001);
				message = "(init (version 15))";
				break;
			case 'c':
				this.connect = new Connect(hostname, 6002);
				message = message + ")";
				break;
		}
		this.connect.connectToServer();
		System.out.println("connected");
		this.connect.sendMessage(message);
		message = this.connect.receiveMessage();
		//System.out.println(message);
		message = message.substring(1, message.length() - 1);
		String[] response = message.split(" ");
		if (!response[0].equals("error")) {
			switch (this.typeOfAgent) {
				case 't':
					this.mySide = "trainer";
					break;
				case 'c':
					if (response[1].equals("l")) {
						this.mySide = "left";
					} else {
						this.mySide = "right";
					}
					break;
				default:
					if (response[1].equals("l")) {
						this.mySide = "left";
					} else {
						this.mySide = "right";
					}
					this.number = Integer.parseInt(response[2]);
					break;
			}
			String server = this.connect.receiveMessage();
			//System.out.println(server);
			String player = this.connect.receiveMessage();
			//System.out.println(player);
			this.sender = new Dispatcher(this.connect);
			this.information = new Information(server, player, this.sender, this.mySide, this.teamName, this.number, typeOfAgent);
			int numberTypes = this.information.getReferenceToPlayer().PLAYER_TYPES;
			for (int i = 0; i < numberTypes; i++) {
				String playerType = this.connect.receiveMessage();
				//System.out.println(playerType);
				this.information.getReferenceToPlayer().addPlayerType(playerType);
			}
			this.reader = new Reader(this.connect, this.information, this.number);
			this.commands = new Commands(this.sender, this.information);
			new Thread(this.reader).start();
			this.isConnected = true;
			System.out.println("connected");
		} else {
			throw new Exception("Error at trying to connect to server");
		}
	}
	
	public void disconnect() {
		if (this.isConnected) {
			this.information.getReferenceToGame().turnOnLogicalTime();
			this.reader.shutdown();
			this.connect.sendMessage("(bye)");
			this.isConnected = false;
			this.connect.close();
			this.information.shutdown();
		}
	}
	
	public boolean isConnected() {
		return this.isConnected;
	}
	
	public Game getReferenceToGame() throws Exception {
		if (this.isConnected) {
			return this.information.getReferenceToGame();
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
	public WorldModelFactory getReferenceToWorldModel() throws Exception {
		if (this.isConnected) {
			return this.information.getWorldModelFactory();
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
	public BallModelFactory getReferenceToBallModel() throws Exception {
		if (this.isConnected) {
			return this.information.getBallModelFactory();
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
	public Self getReferenceToPlayer() throws Exception {
		if (this.isConnected) {
			return this.information.getReferenceToPlayer();
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
	public Commands getReferenceToCommands() throws Exception {
		if (this.isConnected) {
			return this.commands;
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
	public Messages getReferenceToMessages() throws Exception {
		if (this.isConnected) {
			return this.information.getReferenceToMessages();
		} else {
			throw new Exception("The agent is not connected");
		}
	}
	
}
